package com.github.jspxnet.worktask.service.impl;

import com.github.jspxnet.enums.AuditEnumType;
import com.github.jspxnet.enums.YesNoEnumType;
import com.github.jspxnet.sioc.annotation.Bean;
import com.github.jspxnet.sioc.annotation.Ref;
import com.github.jspxnet.txweb.AssertException;
import com.github.jspxnet.txweb.annotation.Transaction;
import com.github.jspxnet.txweb.util.MemberUtil;
import com.github.jspxnet.utils.StringUtil;
import com.github.jspxnet.worktask.core.node.*;
import com.github.jspxnet.worktask.dao.ConfWorkFlowDAO;
import com.github.jspxnet.worktask.dao.RuntimeServiceDAO;
import com.github.jspxnet.worktask.dao.UserAdapterDAO;
import com.github.jspxnet.worktask.env.JWorkTask;
import com.github.jspxnet.worktask.listener.TaskListenerManager;
import com.github.jspxnet.worktask.model.dto.ProcessResponse;
import com.github.jspxnet.worktask.model.enums.FlowNodeEnumType;
import com.github.jspxnet.worktask.model.enums.GatewayEnumType;
import com.github.jspxnet.worktask.model.param.WorkTaskParam;
import com.github.jspxnet.worktask.service.RuntimeService;
import com.github.jspxnet.worktask.table.*;
import com.github.jspxnet.worktask.util.WorkFlowUtil;
import java.util.*;

@Bean(namespace = JWorkTask.namespace)
public class RuntimeServiceImpl implements RuntimeService {
    @Ref
    private ConfWorkFlowDAO confWorkFlowDAO;

    @Ref
    private UserAdapterDAO userAdapterDAO;

    @Ref
    private RuntimeServiceDAO runtimeServiceDAO;

    /**
     *
     * @param workTaskParam 流程参数
     * @return 启动一个流程
     */
    @Override
    public ProcessResponse<?> start(WorkTaskParam workTaskParam)
    {
        return start(workTaskParam, new HashMap<>(0));
    }

    /**
     * @param workTaskParam 节点动作
     * @param variables     变量
     * @return 返回状态
     */
    @Transaction
    @Override
    public ProcessResponse<?> start(WorkTaskParam workTaskParam, Map<String, Object> variables)
    {
        if (StringUtil.isNull(workTaskParam.getFlowNo())) {
            return ProcessResponse.error("flowNo流程编号不能为空");
        }
        if (StringUtil.isNull(workTaskParam.getNamespace())) {
            return ProcessResponse.error("namespace命名空间不能为空");
        }
        if (StringUtil.isNull(workTaskParam.getDocumentNo())) {
            return ProcessResponse.error("documentNo文档编号不能为空");
        }

        if (!runtimeServiceDAO.canStart(workTaskParam.getFlowNo(), workTaskParam.getNamespace(),workTaskParam.getDocumentNo()))
        {
            return ProcessResponse.error(workTaskParam.getDocumentNo()+ "文档已经发起过流程");
        }

        ConfWorkFlow confWorkFlow = confWorkFlowDAO.getByFlowNo(workTaskParam.getFlowNo(), workTaskParam.getNamespace());
        ConfFlowNode confFlowNode = WorkFlowUtil.getStartConfWorkFlow(confWorkFlow);
        if (!userAdapterDAO.isAuthority(confFlowNode, workTaskParam.getUserId())) {
            return ProcessResponse.error("没有权限不能发起流程");
        }
        BaseNodeAction baseNodeAction = new StartNodeAction();
        baseNodeAction.setRuntimeServiceDAO(runtimeServiceDAO);
        baseNodeAction.setConfWorkFlowDAO(confWorkFlowDAO);
        baseNodeAction.setUserAdapterDAO(userAdapterDAO);
        baseNodeAction.setCurrentConfFlowNode(confFlowNode);
        baseNodeAction.setWorkTaskParam(workTaskParam);
        baseNodeAction.setVariables(variables);
        return baseNodeAction.execute();
    }

    /**
     *
     * @param workTaskParam 任务参数
     * @return 得到当前文档任务
     */
    @Override
    public List<WorkTask> getCurrentDocumentWorkTask(WorkTaskParam workTaskParam)
    {
        if (StringUtil.isNull(workTaskParam.getFlowNo())) {
            return new ArrayList<>(0);
        }
        if (StringUtil.isNull(workTaskParam.getNamespace())) {
            return new ArrayList<>(0);
        }
        if (StringUtil.isNull(workTaskParam.getDocumentNo())) {
            return new ArrayList<>(0);
        }
        List<WorkTask> workTaskList = runtimeServiceDAO.getWorkTaskList(workTaskParam.getFlowNo(), workTaskParam.getNamespace(), workTaskParam.getDocumentNo());
        if (StringUtil.isNull(workTaskParam.getUserId()))
        {
            return workTaskList;
        }

        List<WorkTask> result = new ArrayList<>();
        for (WorkTask workTask:workTaskList)
        {
            if (workTaskParam.getUserId().equals(MemberUtil.getUserId(workTask.getUsers())))
            {
                result.add(workTask);
            }
        }
        return result;
    }

    /**
     * @param workTaskParam 变量
     * @return 得到用户当前的代办任务列表
     */
    @Override
    public List<String> getDocumentList(WorkTaskParam workTaskParam,int currentPage, int count)
    {
        return runtimeServiceDAO.getDocumentList(workTaskParam.getFlowNo(), workTaskParam.getNamespace(),currentPage,count);
    }

    /**
     *
     * @param workTaskParam 流程参数
     * @return 得到当前待执行的任务
     */
    @Override
    public List<WorkTask> getCurrentWorkTask(WorkTaskParam workTaskParam)
    {
        AssertException.isNull(workTaskParam.getFlowNo(),"flowNo流程编号不能为空");
        AssertException.isNull(workTaskParam.getNamespace(),"namespace命名空间不能为空");
        List<WorkTask> workTaskList = runtimeServiceDAO.getWorkTaskList(workTaskParam.getFlowNo(), workTaskParam.getNamespace());
        if (StringUtil.isNull(workTaskParam.getUserId()))
        {
            return workTaskList;
        }

        List<WorkTask> result = new ArrayList<>();
        for (WorkTask workTask:workTaskList)
        {
            if (workTaskParam.getUserId().equals(MemberUtil.getUserId(workTask.getUsers())))
            {
                result.add(workTask);
            }
        }
        return result;
    }

    /**
     * 执行当前节点任务
     * @param workTaskParam 参数
     * @return 返回执行结果
     */
    @Override
    public ProcessResponse<?> complete(WorkTaskParam workTaskParam)
    {
        return complete(workTaskParam, new HashMap<>(0));
    }
    /**
     * 执行到一下一节点
     * @param workTaskParam 参数
     * @param variables 变量
     * @return 返回执行结果
     */
    @Transaction
    @Override
    public ProcessResponse<?> complete(WorkTaskParam workTaskParam, Map<String, Object> variables)
    {
        if (StringUtil.isNull(workTaskParam.getFlowNo())) {
            return ProcessResponse.error("flowNo流程编号不能为空");
        }
        if (StringUtil.isNull(workTaskParam.getNamespace())) {
            return ProcessResponse.error("namespace命名空间不能为空");
        }
        if (StringUtil.isNull(workTaskParam.getDocumentNo())) {
            return ProcessResponse.error("documentNo文档编号不能为空");
        }
        if (StringUtil.isNull(workTaskParam.getUserId())) {
            return ProcessResponse.error("userId用户ID不能为空");
        }

        if (AuditEnumType.NO.getValue() == workTaskParam.getAuditType()) {
            DocumentFlowConf documentFlowConf = confWorkFlowDAO.getDocumentFlowConf(workTaskParam.getFlowNo(), workTaskParam.getNamespace());
            if (documentFlowConf!=null&&YesNoEnumType.NO.getValue()==documentFlowConf.getCanEmptyOpinion() && StringUtil.isNull(workTaskParam.getNote()))
            {
                return ProcessResponse.error("驳回必须填写原因");
            }
        }


        TaskListenerManager taskListenerManager = TaskListenerManager.getInstance();
        LinkedList<ProcessResponse<?>> processResponseList = new LinkedList<>();
        List<WorkTask> workTaskList = runtimeServiceDAO.getWorkTaskList(workTaskParam.getFlowNo(), workTaskParam.getNamespace(), workTaskParam.getDocumentNo());

        for (WorkTask task : workTaskList) {
            //这里是多个,说明task是一个 分支节点 节点
            ConfFlowNode currentConfFlowNode = confWorkFlowDAO.getConfFlowNode(workTaskParam.getFlowNo(), workTaskParam.getNamespace(), task.getNodeId());
            if (currentConfFlowNode == null || currentConfFlowNode.getId() <= 0) {
                return ProcessResponse.error("当前节点为空,配置存在异常");
            }

            //先判断权限begin
            if (!userAdapterDAO.isAuthority(currentConfFlowNode,workTaskParam.getUserId()))
            {
                //"没有权限"
                continue;
            }
            //先判断权限end

            if (currentConfFlowNode.getFlowNodeType() == FlowNodeEnumType.GATEWAY.getValue()
                    && GatewayEnumType.FORK.getValue() == currentConfFlowNode.getGatWayType()) {
                //分支
                BaseNodeAction baseNodeAction = new ForkNodeAction();
                baseNodeAction.setRuntimeServiceDAO(runtimeServiceDAO);
                baseNodeAction.setConfWorkFlowDAO(confWorkFlowDAO);
                baseNodeAction.setUserAdapterDAO(userAdapterDAO);
                baseNodeAction.setCurrentConfFlowNode(currentConfFlowNode);
                baseNodeAction.setCurrentWorkTask(task);
                baseNodeAction.setWorkTaskParam(workTaskParam);
                baseNodeAction.setVariables(variables);
                processResponseList.add(baseNodeAction.execute());

            } else if (currentConfFlowNode.getFlowNodeType() == FlowNodeEnumType.GATEWAY.getValue()
                    && GatewayEnumType.JOIN.getValue() == currentConfFlowNode.getGatWayType()) {
                //合并 当前的节点不会等于合并,这里不会执行
                BaseNodeAction baseNodeAction = new JoinNodeAction();
                baseNodeAction.setRuntimeServiceDAO(runtimeServiceDAO);
                baseNodeAction.setConfWorkFlowDAO(confWorkFlowDAO);
                baseNodeAction.setUserAdapterDAO(userAdapterDAO);
                baseNodeAction.setCurrentConfFlowNode(currentConfFlowNode);
                baseNodeAction.setCurrentWorkTask(task);
                baseNodeAction.setWorkTaskParam(workTaskParam);
                baseNodeAction.setVariables(variables);
                processResponseList.add(baseNodeAction.execute());

            } else if (FlowNodeEnumType.TASK.getValue() == currentConfFlowNode.getFlowNodeType()) {

                //任务 一般是手工,或者自动触发的任务动作
                BaseNodeAction baseNodeAction = new TaskNodeAction();
                baseNodeAction.setRuntimeServiceDAO(runtimeServiceDAO);
                baseNodeAction.setConfWorkFlowDAO(confWorkFlowDAO);
                baseNodeAction.setUserAdapterDAO(userAdapterDAO);
                baseNodeAction.setCurrentConfFlowNode(currentConfFlowNode);
                baseNodeAction.setCurrentWorkTask(task);
                baseNodeAction.setWorkTaskParam(workTaskParam);
                baseNodeAction.setVariables(variables);
                processResponseList.add(baseNodeAction.execute());
            }
            taskListenerManager.notifyAll(task);
        }
        processResponseList.remove(null);
        if (processResponseList.isEmpty()) {
            return ProcessResponse.error("没有可执行的流程");
        }
        return processResponseList.getLast();
    }


    /**
     *
     * @param workTaskParam 单步回退
     * @return 单步回退
     */
    @Override
    public ProcessResponse<?> singleResult(WorkTaskParam workTaskParam)
    {
        if (StringUtil.isNull(workTaskParam.getFlowNo())) {
            return ProcessResponse.error("flowNo流程编号不能为空");
        }
        if (StringUtil.isNull(workTaskParam.getNamespace())) {
            return ProcessResponse.error("namespace命名空间不能为空");
        }
        if (StringUtil.isNull(workTaskParam.getDocumentNo())) {
            return ProcessResponse.error("documentNo文档编号不能为空");
        }
        if (StringUtil.isNull(workTaskParam.getUserId())) {
            return ProcessResponse.error("userId用户ID不能为空");
        }
        LinkedList<ProcessResponse<?>> processResponseList = new LinkedList<>();
        List<WorkTask> workTaskList = runtimeServiceDAO.getWorkTaskList(workTaskParam.getFlowNo(), workTaskParam.getNamespace(), workTaskParam.getDocumentNo());
        for (WorkTask task : workTaskList) {
            ConfFlowNode currentConfFlowNode = confWorkFlowDAO.getConfFlowNode(workTaskParam.getFlowNo(), workTaskParam.getNamespace(), task.getNodeId());
            if (currentConfFlowNode == null || currentConfFlowNode.getId() <= 0) {
                return ProcessResponse.error("当前节点为空,配置存在异常");
            }
            BaseNodeAction baseNodeAction = new ForkNodeAction();
            baseNodeAction.setRuntimeServiceDAO(runtimeServiceDAO);
            baseNodeAction.setConfWorkFlowDAO(confWorkFlowDAO);
            baseNodeAction.setUserAdapterDAO(userAdapterDAO);
            baseNodeAction.setCurrentConfFlowNode(currentConfFlowNode);
            baseNodeAction.setCurrentWorkTask(task);
            baseNodeAction.setWorkTaskParam(workTaskParam);
            processResponseList.add(baseNodeAction.execute());
        }
        return processResponseList.getLast();
    }

    /**
     *
     * @param workTaskParam 参数
     * @return 删除文档的所有流程
     */
    @Override
    public int deleteDocumentTask(WorkTaskParam workTaskParam) {
        AssertException.isNull(workTaskParam.getFlowNo(),"flowNo流程编号不能为空");
        AssertException.isNull(workTaskParam.getNamespace(),"namespace命名空间不能为空");
        AssertException.isNull(workTaskParam.getDocumentNo(),"documentNo文档编号不能为空");
        return runtimeServiceDAO.deleteWorkTask(workTaskParam.getFlowNo(),workTaskParam.getNamespace(),workTaskParam.getDocumentNo());
    }

}
